#include "pch.h"
#include "voxelBrush.h"
namespace mini
{
	CVoxelBrush* CVoxelBrush::GVoxelBrush = nullptr;
	CVoxelBrush::CVoxelBrush()
	{
		GVoxelBrush = this;
	}
	CVoxelBrush::~CVoxelBrush()
	{
		mpActor = nullptr;
	}

	void CVoxelBrush::convertToVoxel(CActor* pActor)
	{
		mpActor = pActor;
		mPosition = pActor->getPosition();
		if (nullptr != mpActor)
		{
			float fOffset = 0.25f;
			mBoundBox = mpActor->getBoundBox();
			auto fMin = mBoundBox.getMinPos();
			auto fMax = mBoundBox.getMaxPos();
			fMin.x -= mPosition.x;
			fMin.y -= mPosition.y;
			fMin.z -= mPosition.z;

			fMax.x -= mPosition.x;
			fMax.y -= mPosition.y;
			fMax.z -= mPosition.z;

			int xLength = (fMax.x - fMin.x) / mVoxelSize;
			int yLength = (fMax.y - fMin.y) / mVoxelSize;
			int zLength = (fMax.z - fMin.z) / mVoxelSize;
			mVoxelRecord.resize(xLength);
			for (int i = 0; i < xLength; ++i)
			{
				mVoxelRecord[i].resize(yLength);
				for (int j = 0; j < yLength; ++j)
				{
					mVoxelRecord[i][j].resize(zLength, std::make_pair(0, nullptr));
				}
			}
			auto leftRightDir = [&]()
			{
				CVector fDir = { 1, 0, 0 };
				for (float z = fMin.z; z <= fMax.z; z += mVoxelSize)
				{
					for (float y = fMin.y; y <= fMax.y; y += mVoxelSize)
					{
						CVector fOrginMin = { fMin.x - fOffset, y, z };
						auto fMinResult = pActor->isPick(fOrginMin, fDir, false);
						if (fMinResult.first)
						{
							float fRangMin = fOrginMin.x + fMinResult.second;
							CVector fOrginMax = fOrginMin;
							fOrginMax.x = -fOrginMin.x;
							auto fMaxResult = pActor->isPick(fOrginMax, -fDir, false);

							if (fMaxResult.first)
							{
								float fRangMax = fOrginMax.x - fMaxResult.second;
								for (float x = fRangMin; x <= fRangMax; x += mVoxelSize)
								{
									int nX = (x - fMin.x) / mVoxelSize; 
									if (nX >= mVoxelRecord.size())
									{
										break;
									}
									int nY = (y - fMin.y) / mVoxelSize;
									if (nY >= mVoxelRecord[nX].size())
									{
										break;
									}
									int nZ = (z - fMin.z) / mVoxelSize;
									if (nZ >= mVoxelRecord[nX][nY].size())
									{
										break;
									}
									mVoxelRecord[nX][nY][nZ].first = 1;

									//CPoint3F minPos = { fMin.x + nX * mVoxelSize, fMin.y + nY * mVoxelSize, fMin.z + nZ * mVoxelSize };
									//CPoint3F maxPos = { minPos.x + mVoxelSize, minPos.y + mVoxelSize, minPos.z + mVoxelSize };

									//CBlock* pBlock = new CBlock;
									//pBlock->setSize(minPos, maxPos);
									//pBlock->buildVoxelMesh();

								}
							}
						}
					}
				}
			};

			auto frontBackDir = [&]()
			{
				CVector fDir = { 0, 0, 1 };
				for (float x = fMin.x; x <= fMax.x; x += mVoxelSize)
				{
					for (float y = fMin.y; y <= fMax.y; y += mVoxelSize)
					{
						CVector fOrginMin = { x, y, fMin.z - fOffset };
						auto fMinResult = pActor->isPick(fOrginMin, fDir, false);
						if (fMinResult.first)
						{
							float fRangMin = fOrginMin.z + fMinResult.second;
							CVector fOrginMax = fOrginMin;
							fOrginMax.z = -fOrginMin.z;
							auto fMaxResult = pActor->isPick(fOrginMax, -fDir, false);

							if (fMaxResult.first)
							{
								float fRangMax = fOrginMax.z - fMaxResult.second;
								for (float z = fRangMin; z <= fRangMax; z += mVoxelSize)
								{
									int nX = (x - fMin.x) / mVoxelSize;
									if (nX >= mVoxelRecord.size())
									{
										break;
									}
									int nY = (y - fMin.y) / mVoxelSize;
									if (nY >= mVoxelRecord[nX].size())
									{
										break;
									}
									int nZ = (z - fMin.z) / mVoxelSize;
									if (nZ >= mVoxelRecord[nX][nY].size())
									{
										break;
									}
									if (1 == mVoxelRecord[nX][nY][nZ].first)
									{
										mVoxelRecord[nX][nY][nZ].first = 2;
									}
									//CPoint3F minPos = { fMin.x + nX * mVoxelSize, fMin.y + nY * mVoxelSize, fMin.z + nZ * mVoxelSize };
									//CPoint3F maxPos = { minPos.x + mVoxelSize, minPos.y + mVoxelSize, minPos.z + mVoxelSize };

									//CBlock* pBlock = new CBlock;
									//pBlock->setSize(minPos, maxPos);
									//pBlock->buildVoxelMesh();
								}

							}
						}
					}
				}
			};

			auto downUpDir = [&]()
			{
				CVector fDir = { 0, 1, 0 };
				for (float x = fMin.x; x <= fMax.x; x += mVoxelSize)
				{
					for (float z = fMin.z; z <= fMax.x; z += mVoxelSize)
					{
						CVector fOrginMin = { x, fMin.y, z };
						auto fMinResult = pActor->isPick(fOrginMin, fDir, false);
						if (fMinResult.first)
						{
							float fRangMin = fOrginMin.y + fMinResult.second;
							CVector fOrginMax = fOrginMin;
							fOrginMax.y = fMax.y;
							auto fMaxResult = pActor->isPick(fOrginMax, -fDir, false);

							if (fMaxResult.first)
							{
								float fRangMax = fOrginMax.y - fMaxResult.second;
								for (float y = fRangMin; y <= fRangMax; y += mVoxelSize)
								{
									int nX = (x - fMin.x) / mVoxelSize;
									if (nX >= mVoxelRecord.size())
									{
										break;
									}
									int nY = (y - fMin.y) / mVoxelSize;
									if (nY >= mVoxelRecord[nX].size())
									{
										break;
									}
									int nZ = (z - fMin.z) / mVoxelSize;
									if (nZ >= mVoxelRecord[nX][nY].size())
									{
										break;
									}
									if (2 == mVoxelRecord[nX][nY][nZ].first)
									{
										mVoxelRecord[nX][nY][nZ].first = 3;
									}
									//CPoint3F minPos = { fMin.x + nX * mVoxelSize, fMin.y + nY * mVoxelSize, fMin.z + nZ * mVoxelSize };
									//CPoint3F maxPos = { minPos.x + mVoxelSize, minPos.y + mVoxelSize, minPos.z + mVoxelSize };

									//CBlock* pBlock = new CBlock;
									//pBlock->setSize(minPos, maxPos);
									//pBlock->buildVoxelMesh();
								}

							}
						}
					}
				}
			};
			leftRightDir();
			frontBackDir();
			downUpDir();
			for (int x = 0; x < mVoxelRecord.size(); ++x)
			{
				for (int y = 0; y < mVoxelRecord[x].size(); ++y)
				{
					for (int z = 0; z < mVoxelRecord[x][y].size(); ++z)
					{
						if (3 == mVoxelRecord[x][y][z].first)
						{
							CPoint3F minPos = { fMin.x + x * mVoxelSize, fMin.y + y * mVoxelSize, fMin.z + z * mVoxelSize };
							CPoint3F maxPos = { minPos.x + mVoxelSize, minPos.y + mVoxelSize, minPos.z + mVoxelSize };

							CBlockNode* pBlock = new CBlockNode;
							pBlock->setSize(minPos, maxPos);
							//pBlock->buildVoxelMesh(mpActor->getPosition());
							mVoxelRecord[x][y][z].first = 1;
							mVoxelRecord[x][y][z].second = pBlock;
						}
						else
						{
							mVoxelRecord[x][y][z].first = 0;
						}
					}
				}
			}
		}
		mpActor->setVisible(true);
	}

	void CVoxelBrush::setPosition(const CVector& pos)
	{
		CVector offset = pos - mPosition;
		mPosition = pos;
		mpActor->setPosition(pos);
		mBoundBox = mpActor->getBoundBox();
		//for (int x = 0; x < mVoxelRecord.size(); ++x)
		//{
		//	for (int y = 0; y < mVoxelRecord[x].size(); ++y)
		//	{
		//		for (int z = 0; z < mVoxelRecord[x][y].size(); ++z)
		//		{
		//			auto pNode = mVoxelRecord[x][y][z].second;
		//			if(nullptr != pNode)
		//			{
		//				pNode->setPosition(pos);
		//			}
		//		}
		//	}
		//}
	}

	CVector CVoxelBrush::getPosition()
	{
		return mPosition;
	}

	CBoundBox* CVoxelBrush::getBoundBoxPtr()
	{
		if(nullptr != mpActor)
		{
			return &mpActor->getBoundBox();
		}
		else
		{
			return nullptr;
		}
	}

	bool CVoxelBrush::checkBlockNode(CBlockNode* pBlockNode, bool bIncrease)
	{
		if (mBoundBox.checkBoundBox(*pBlockNode->mpBound))
		{
			int cubeIndex = pBlockNode->mCubeIndex;
			if (bIncrease)
			{
				/*if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[0].position))
				{
					cubeIndex |= 1;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[1].position))
				{
					cubeIndex |= 2;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[2].position))
				{
					cubeIndex |= 4;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[3].position))
				{
					cubeIndex |= 8;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[4].position))
				{
					cubeIndex |= 16;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[5].position))
				{
					cubeIndex |= 32;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[6].position))
				{
					cubeIndex |= 64;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[7].position))
				{
					cubeIndex |= 128;
				}*/
				int it = 0;
				for (int i = 0; i < 8; ++i)
				{
					if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[i].position))
					{
						++it;
						cubeIndex |= (1 << i);
					}
				}
				if (it == 8)
				{
					int x = 0;
				}
			}
			else
			{
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[0].position))
				{
					cubeIndex &= ~1;	
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[1].position))
				{
					cubeIndex &= ~2;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[2].position))
				{
					cubeIndex &= ~4;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[3].position))
				{
					cubeIndex &= ~8;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[4].position))
				{
					cubeIndex &= ~16;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[5].position))
				{
					cubeIndex &= ~32;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[6].position))
				{
					cubeIndex &= ~64;
				}
				if (mBoundBox.checkPoint(pBlockNode->mVerticesOriginal[7].position))
				{
					cubeIndex &= ~128;
				}
			}
			pBlockNode->mCubeIndex = cubeIndex;
			pBlockNode->buildMeshEx();
			return true;
		}
		return false;
	}

	void CVoxelBrush::testPlane(int showZ)
	{
		for (int x = 0; x < mVoxelRecord.size(); ++x)
		{
			for (int y = 0; y < mVoxelRecord[x].size(); ++y)
			{
				for (int z = 0; z < mVoxelRecord[x][y].size(); ++z)
				{
					if (nullptr != mVoxelRecord[x][y][z].second)
					{
						mVoxelRecord[x][y][z].second->mpActor->setVisible(false);
					}
				}
			}
		}
		for (int x = 0; x < mVoxelRecord.size(); ++x)
		{
			for (int y = 0; y < mVoxelRecord[x].size(); ++y)
			{
				for (int z = 0; z < mVoxelRecord[x][y].size(); ++z)
				{
					if (z == showZ && mVoxelRecord[x][y][z].second != nullptr)
					{
						mVoxelRecord[x][y][z].second->mpActor->setVisible(true);
					}
				}
			}
		}
	}

}